import json

from redis.asyncio import Redis
from sqlalchemy.ext.asyncio import AsyncSession

from exceptions.exception import ServiceException
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_stock.dao.trade_dao import TradeDao
from module_stock.entity.vo.trade_vo import DeleteTradeModel, TradeModel, TradePageQueryModel, UpdateTradeStatusModel
from module_xtquant.xtdata_subscription_manager import xtdata_subscription_manager
from utils.association_util import process_associated_data
from utils.common_util import CamelCaseUtil


class TradeService:
    """
    股票交易任务模块服务层
    """

    @classmethod
    async def get_trade_list_services(
            cls, query_db: AsyncSession, query_object: TradePageQueryModel, is_page: bool = False
    ):
        """
        获取股票交易任务列表信息service
        :param query_db: orm对象
        :param query_object: 查询参数对象
        :param is_page: 是否开启分页
        :return: 股票交易任务列表信息对象
        """
        trade_list_result = await TradeDao.get_trade_list(query_db, query_object, is_page)
        # 定义关联映射: 目标字段 -> 源数据索引
        association_mapping = {'stockName': 1}
        trade_list_result = process_associated_data(trade_list_result, association_mapping, '', is_page)
        return trade_list_result

    @classmethod
    async def add_trade_services(cls, redis: Redis, query_db: AsyncSession, page_object: TradeModel):
        """
        新增股票交易任务信息service
        :param redis : redis
        :param query_db: orm对象
        :param page_object: 新增股票交易任务对象
        :return: 新增股票交易任务校验结果
        """
        try:
            await TradeDao.add_trade_dao(query_db, page_object)
            await query_db.commit()
            await cls.reload_trade_tasks_to_redis(redis, query_db)
            return CrudResponseModel(is_success=True, message='新增成功')
        except Exception as e:
            await query_db.rollback()
            raise e

    @classmethod
    async def edit_trade_services(cls, redis: Redis, query_db: AsyncSession, page_object: TradeModel):
        """
        编辑股票交易任务信息service
        :param redis : redis
        :param query_db: orm对象
        :param page_object: 编辑股票交易任务对象
        :return: 编辑股票交易任务校验结果
        """
        edit_trade = page_object.model_dump(exclude_unset=True,
                                            exclude={'phase', 'create_by', 'create_time'})
        trade_info = await cls.trade_detail_services(query_db, page_object.id)
        if trade_info.id:
            try:
                await TradeDao.edit_trade_dao(query_db, edit_trade)
                await query_db.commit()
                await cls.reload_trade_tasks_to_redis(redis, query_db)
                return CrudResponseModel(is_success=True, message='更新成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='股票交易任务不存在')

    @classmethod
    async def delete_trade_services(cls, query_db: AsyncSession, page_object: DeleteTradeModel):
        """
        删除股票交易任务信息service

        :param query_db: orm对象
        :param page_object: 删除股票交易任务对象
        :return: 删除股票交易任务校验结果
        """
        if page_object.ids:
            id_list = page_object.ids.split(',')
            try:
                for id in id_list:
                    await TradeDao.delete_trade_dao(query_db, TradeModel(id=id))
                await query_db.commit()
                return CrudResponseModel(is_success=True, message='删除成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='传入主键ID为空')

    @classmethod
    async def trade_detail_services(cls, query_db: AsyncSession, id: int):
        """
        获取股票交易任务详细信息service

        :param query_db: orm对象
        :param id: 主键ID
        :return: 主键ID对应的信息
        """
        trade = await TradeDao.get_trade_detail_by_id(query_db, id=id)
        if trade:
            result = TradeModel(**CamelCaseUtil.transform_result(trade))
        else:
            result = TradeModel(**dict())

        return result

    @classmethod
    async def update_trade_status_services(cls, redis: Redis, query_db: AsyncSession,
                                           update_status: UpdateTradeStatusModel):
        """
        更新股票交易任务状态service
        :param redis : redis
        :param query_db: orm对象
        :param update_status: 更新股票交易任务状态对象
        :return: 更新股票交易任务状态校验结果
        """
        trade_info = await cls.trade_detail_services(query_db, update_status.id)
        if trade_info.id:
            try:
                update_data = {
                    "id": update_status.id,
                    "status": update_status.status,
                    "update_by": update_status.update_by,
                    "update_time": update_status.update_time
                }
                await TradeDao.edit_trade_dao(query_db, update_data)
                await query_db.commit()
                await cls.reload_trade_tasks_to_redis(redis, query_db)
                return CrudResponseModel(is_success=True, message='更新状态成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='交易任务不存在')

    @classmethod
    async def reload_trade_tasks_to_redis(cls, redis: Redis, query_db):
        """
        清空Redis中的交易任务数据并重新加载

        :param redis: redis
        :param query_db: 数据库会话对象
        """
        # 先清空所有相关的redis数据
        keys_to_delete = await redis.keys("trade_tasks:*")
        if keys_to_delete:
            await redis.delete(*keys_to_delete)

        query_model = TradePageQueryModel(status="2")  # 假设"监控中"是任务的监控状态
        trade_tasks = await TradeDao.get_trade_list(query_db, query_model, is_page=False)
        for row in trade_tasks:
            trade_task = row[0]
            stock_code = trade_task.get("stockCode")
            xtdata_subscription_manager().add_subscription(stock_code)
            redis_key = f"trade_tasks:{stock_code}"
            task_dict = {
                'id': trade_task.get("id"),
                'stock_code': stock_code,
                'direction': trade_task.get("direction"),
                'price': str(trade_task.get("price")),
                'quantity': trade_task.get("quantity"),
                'source': trade_task.get("source"),
                'account_no': trade_task.get("accountNo"),
                'phase': trade_task.get("phase"),
                'status': trade_task.get("status"),
                'remark': trade_task.get("remark")
            }
            await redis.lpush(redis_key, json.dumps(task_dict))
